package main

import (
	"go/ast"
)

type File struct {
	Package string
	Imports []string
	Types   []*Type
}

type Type struct {
	Name   string
	Fields []*Field
}

type Field struct {
	Name string
	Type string
}

type SingleFileEntryVisitor struct {
	f *File
}

type FileVisitor struct {
	f *File
}

type TypeVisitor struct {
	t *Type
}

func (s *SingleFileEntryVisitor) Visit(node ast.Node) (w ast.Visitor) {
	fn, ok := node.(*ast.File)
	if !ok {
		return s
	}
	//fn.Name
	s.f = &File{}
	s.f.Package = fn.Name.String()
	return &FileVisitor{
		f: s.f,
	}
}

func (f *FileVisitor) Visit(node ast.Node) (w ast.Visitor) {
	switch n := node.(type) {
	case *ast.TypeSpec:
		t := &Type{
			Name: n.Name.String(),
		}
		f.f.Types = append(f.f.Types, t)
		return &TypeVisitor{
			t: t,
		}
	case *ast.ImportSpec:
		path := n.Path.Value
		if n.Name != nil && n.Name.String() != "" {
			path = n.Name.String() + " " + path
		}
		f.f.Imports = append(f.f.Imports, path)

	}

	return f
}

func (t *TypeVisitor) Visit(node ast.Node) (w ast.Visitor) {
	n, ok := node.(*ast.Field)
	if !ok {
		return t
	}
	var typ string
	switch nt := n.Type.(type) {
	case *ast.Ident:
		typ = nt.String()
	case *ast.StarExpr:
		switch xt := nt.X.(type) {
		case *ast.Ident:
			typ = "*" + xt.String()
		case *ast.SelectorExpr:
			typ = "*" + xt.X.(*ast.Ident).String() + "." + xt.Sel.String()
		}
	case *ast.ArrayType:
		typ = "[]byte"
	default:
		panic("不支持的类型")
	}
	for _, name := range n.Names {
		t.t.Fields = append(t.t.Fields, &Field{
			Name: name.String(),
			Type: typ,
		})
	}
	return t
}
